package com.abl.lib.common.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 凭证签发工具
 *
 * @author WangYongJi
 */
@Slf4j
public class JwtKit {
    //    🔑HMAC 密钥长度和安全性
    //    当使用基于哈希的消息验证码，例如 HS256 或 HS512 时，为了遵守 JSON Web 算法 (JWA) 规范 (RFC7518) 的严格要求，您必须使用具有相同（或更大）的密钥位长度作为输出哈希的大小。
    //    这是为了避免削弱验证码的安全强度（参见 NIST 建议 NIST SP 800-117）。
    //    例如，使用 HMAC256 时，密钥长度必须至少为 256 位。
    //秘钥
    private static final String secret;
    //签名算法(HMAC256)
    private static Algorithm algorithm256;
    //签名验证工具
    private static JWTVerifier jwtVerifier;

    static {
        secret = FileKit.fileTextContent(FileKit.getClassPath("src/main/resources/secret"));
        if (secret == null) {
            System.out.println("JwtKit异常：秘钥读取失败，请检查类路径下，是否存在 “secret” 文件");
        } else {
            algorithm256 = Algorithm.HMAC256(secret);
            jwtVerifier = JWT.require(algorithm256).build();
        }
    }

    /**
     * 生成Token
     *
     * @param param 携带参数，通过getParam方法读取参数
     * @param hour  失效时间(小时)
     * @return 生成签名字符串
     */
    public static String createToken(Map<Object, Object> param, Object hour) {
        //过期时间,默认两小时
        if (hour == null) hour = 2;
        Date expireDate = new Date(new Date().getTime() + (Long.parseLong(hour.toString()) * 60 * 60 * 1000));

        //
        if (param == null) {
            param = new HashMap<>();
        }
        param.put("withExpiresAt", DateKit.dateToStr(expireDate));
        param.put("createTime", DateKit.dateToStr(new Date()));
        return JWT.create()
                .withClaim("param", JSON.toJSONString(param))//可读取的参数信息（别存太多）
                .withExpiresAt(expireDate)//超时时间
                .sign(algorithm256); //signature
    }

    //生成Token
    public static String createToken(Map<Object, Object> param) {
        return createToken(param, null);
    }

    //生成Token
    public static String createToken(Object time) {
        return createToken(null, time);
    }

    //检查失效
    public static boolean check(Object token) {
        if (ObjectUtils.isEmpty(token)) return false;
        try {
            jwtVerifier.verify(token.toString());
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获取整个参数对象
     */
    public static JSONObject getParam(String token) {
        return JSON.parseObject(getClaims(token).get("param").asString());
    }

    /**
     * 获取指定 Key 的 Value
     */
    public static Object getParam(String token, String key) {
        return getParam(token).get(key);
    }

    //获取Claims
    private static Map<String, Claim> getClaims(String token) {
        return jwtVerifier.verify(token).getClaims();
    }

    //Token唯一标识符（可用于缓存，作强制退出登录）
    public static String tokenId(String token) {
        return jwtVerifier.verify(token).getId();
    }


//   生成256随机秘钥
//    public static void main(String[] args) {
//        System.out.println(1 / 5);
//        System.out.println(1 % 5);
//        String str1 = "1234567890";
//        String str2 = "abcdefghijklmnopqrstuvwsyz";
//        String str3 = "ABCDEFGHIJKLMNOPQRSTUVWSYZ";
//
//        StringBuilder stringBuilder = new StringBuilder();
//        for (int i = 0; i < 256; i++) {
//            if (i % 5 == 0) {
//                stringBuilder.append(str1.charAt(new Random().nextInt(9)));
//            } else if (i % 3 == 0) {
//                stringBuilder.append(str3.charAt(new Random().nextInt(25)));
//            } else {
//                stringBuilder.append(str2.charAt(new Random().nextInt(25)));
//            }
//        }
//        System.out.println(stringBuilder);
//    }

}
